<?php
/**
 * Model de la Aplicacion.
 *
 *
 * @filesource          
 * @copyright		
 * @link		http://www.pragmatia.com Pragmatia
 * @package		sgpoj
 * @subpackage		
 * @version     1.0
 * @license		http://www.opensource.org/licenses/mit-license.php The MIT License
 * @author      Martin Radosta <mradosta@pragmatia.com>
 */


/**
 * Clase AppModel
 *
 * @package		peusso
 * @subpackage	
 */
class AppModel extends Model
{
	var $name = "";
	var $actsAs   = array('transaction', 'formato', 'ExtendAssociations'); 


    function afterFind($results)  
    {  
        if (isset($this->__runResetExpects) && $this->__runResetExpects) 
        { 
            $this->__resetExpects(); 
            unset($this->__runResetExpects); 
        } 
         
        return parent::afterFind($results); 
    } 
     
    /** 
     * Unbinds all relations from a model except the specified ones. Calling this function without 
     * parameters unbinds all related models. 
     *  
     * @access public 
     * @since 1.0 
     */ 
    function expects()  
    {  
        $models = array(); 
        $arguments = func_get_args(); 
        $innerCall = false; 

        if (!empty($arguments) && is_bool($arguments[0])) 
        { 
            $innerCall = $arguments[0]; 
        } 
         
        foreach($arguments as $index => $argument)  
        {  
            if (is_array($argument))  
            {  
                if (count($argument) > 0)  
                {  
                    $arguments = am($arguments, $argument);  
                }  

                unset($arguments[$index]);  
            } 
        } 
         
        foreach($arguments as $index => $argument) 
        { 
            if (!is_string($argument)) 
            { 
                unset($arguments[$index]); 
            } 
        } 

        if (count($arguments) == 0)  
        {  
            $models[$this->name] = array();  
        }  
        else  
        {  
            foreach($arguments as $argument)  
            {  
                if (strpos($argument, '.') !== false)  
                {  
                    $model = substr($argument, 0, strpos($argument, '.'));  
                    $child = substr($argument, strpos($argument, '.') + 1);  

                    if ($child == $model)  
                    { 
                        $models[$model] = array();  
                    }  
                    else  
                    {  
                        $models[$model][] = $child;  
                    }  
                } 
                else  
                {  
                    $models[$this->name][] = $argument;  
                }  
            }  
        } 
         
        $relationTypes = array ('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany'); 

        foreach($models as $bindingName => $children)  
        { 
            $model = null; 
             
            foreach($relationTypes as $relationType)  
            {  
                $currentRelation = (isset($this->$relationType) ? $this->$relationType : null); 
                 
                if (isset($currentRelation) && isset($currentRelation[$bindingName]) && is_array($currentRelation[$bindingName]) && isset($currentRelation[$bindingName]['className']))  
                { 
                    $model = $currentRelation[$bindingName]['className']; 
                    break; 
                } 
            } 
             
            if (!isset($model)) 
            { 
                $model = $bindingName; 
            } 
             
            if (isset($model) && $model != $this->name && isset($this->$model))  
            { 
                if (!isset($this->__backInnerAssociation)) 
                { 
                    $this->__backInnerAssociation = array(); 
                }  
                 
                $this->__backInnerAssociation[] = $model; 
                 
                $this->$model->expects(true, $children); 
            }  
        } 
         
        if (isset($models[$this->name]))  
        {  
            foreach($models as $model => $children)  
            {  
                if ($model != $this->name)  
                {  
                    $models[$this->name][] = $model;  
                }  
            }  
     
            $models = array_unique($models[$this->name]); 
            $unbind = array();  
     
            foreach($relationTypes as $relation)  
            {  
                if (isset($this->$relation))  
                {  
                    foreach($this->$relation as $bindingName => $bindingData) 
                    {  
                        if (!in_array($bindingName, $models)) 
                        {  
                            $unbind[$relation][] = $bindingName;  
                        }  
                    }  
                }  
            }  
     
            if (count($unbind) > 0)  
            {  
                $this->unbindModel($unbind);  
            } 
        } 

        if (!$innerCall) 
        { 
            $this->__runResetExpects = true; 
        } 
    } 
     
    /** 
     * Resets all relations and inner model relations after calling expects() and find(). 
     *  
     * @access private 
     * @since 1.1 
     */ 
    function __resetExpects() 
    { 
        if (isset($this->__backAssociation)) 
        { 
            $this->__resetAssociations(); 
        } 
         
        if (isset($this->__backInnerAssociation)) 
        { 
            foreach($this->__backInnerAssociation as $model) 
            { 
                $this->$model->__resetExpects(); 
            } 
             
            unset($this->__backInnerAssociation); 
        } 
    } 

/*
    function unbindAll($params = array()) 
    { 
        foreach($this->__associations as $ass) 
        { 
            if(!empty($this->{$ass})) 
            { 
                 $this->__backAssociation[$ass] = $this->{$ass}; 
                if(isset($params[$ass])) 
                { 
                    foreach($this->{$ass} as $model => $detail) 
                    { 
                        if(!in_array($model,$params[$ass])) 
                        { 
                             $this->__backAssociation = array_merge($this->__backAssociation, $this->{$ass}); 
                            unset($this->{$ass}[$model]); 
                        } 
                    } 
                }else 
                { 
                    $this->__backAssociation = array_merge($this->__backAssociation, $this->{$ass}); 
                    $this->{$ass} = array(); 
                } 
                 
            } 
        } 
        return true; 
    }
*/	
/*
Sobreescribe el metodo save del framework con el objeto de guardar de manera transaccional
*/
	function save($registros = array())
	{		
		//solo guardo master/detail cuando es una relacion hasMany y en el vector viene componentes de esta relacion y no otra
		$r =  array_intersect_key($registros, $this->hasMany);
        if(!empty($registros) && isset($this->hasMany) && !empty($this->hasMany) && !empty($r)) 
		{
			$keys = array_keys($registros);
			if ($keys[0] != $this->name) //el primer elemento del vector de keys debe ser el master en el master/datail
				return false;

			array_shift($keys);

			$this->begin(); // Empiezo la transaccion
            if(parent::save($registros[$this->name])) 
			{
				if(isset($this->id) && !empty($this->id))
				{
					$id = $this->id; //es un update, tengo el id del anterior
				}
				else
				{
					$id = $this->getLastInsertId(); //Busco el ultimo id que inserte
				}

				foreach($keys as $key)
				{
					foreach($registros[$key] as $k=>$v)
					{
						$v[$this->hasMany[$key]['foreignKey']] = $id; //le asigno la clave foranea

						//debo decidir si es un update o un insert
						$find = array();
						foreach($this->$key->unique as $unique)
						{
							if(isset($v[$unique]))
							{
								$find[$key . "." . $unique] = $v[$unique];
							}
						}
						if(!empty($find))
						{
							$linea_detalle = $this->$key->find($find, array($this->$key->primaryKey)); 

							if(!empty($linea_detalle)) //el registro ya existe, hay que actualizarlo
							{
								$v[$this->$key->primaryKey] = $linea_detalle[$key][$this->$key->primaryKey];	
							}
							else // el registro no existe (hay que insertarlo)
							{
								$this->$key->create();
							}
						}
						if(!$this->$key->save($v)) {
							$this->rollback(); //vuelvo atras si algo salio mal
							return false;
						}
					}
				}
				$this->commit(); // commiteo
				return true;
            } 
			else 
			{ 
                return false;
            }
        } 
		else
		{
			return parent::save($registros);
		}
	}


	function delete($id)
	{
		//solo borro el detail de un master/detail cuando es una relacion hasMany
        if(isset($this->hasMany) && !empty($this->hasMany)) {
			$this->{$this->primaryKey} = $id;
  			$this->begin(); // Empiezo la transaccion

			foreach($this->hasMany as $k=>$v)
			{
				//d($this->{$v['className']}->primaryKey);
				$this->{$v['className']}->expects();
				$condiciones = $v['className'] . "." . $v['foreignKey'] . " = '" . $id . "'";
				$detalles = $this->{$v['className']}->findAll($condiciones, $this->{$v['className']}->primaryKey);
				if (isset($detalles) && !empty($detalles))
				{
					foreach($detalles as $k1=>$v1)
					{
						//obtengo el id de cada detalle relacionado al master
						$id_detalle = $v1[$v['className']][$this->{$v['className']}->primaryKey];

						if (!$this->{$v['className']}->delete($id_detalle))
						{
							$this->rollback(); //vuelvo atras si algo salio mal
							return false;
						}
					}
				}
			}
			//si ya pude borra sin error todos los details, ahora borro el master
			if (!parent::delete($id))
			{
				$this->rollback(); //vuelvo atras si algo salio mal
				return false;
			}
			$this->commit(); // commiteo
			return true;
		}
		else
		{
			return parent::delete($id);
		}
	}
}

?>
